package com.xunji.standard.service.impl;

import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xunji.standard.cache.CodeBookCache;
import com.xunji.standard.common.Constant;
import com.xunji.standard.dto.ExportData;
import com.xunji.standard.entity.*;
import com.xunji.standard.mapper.CaseMapper;
import com.xunji.standard.service.CaseService;
import com.xunji.standard.service.ExcelProcessService;
import com.xunji.standard.util.*;
import com.xunji.standard.vo.rep.*;
import com.xunji.standard.vo.req.CaseExportRequest;
import com.xunji.standard.vo.req.CaseOwnerUpdateRequest;
import com.xunji.standard.zip.AdvancedCompressionUtils;
import com.xunji.standard.zip.CopyFileDto;
import com.xunji.standard.zip.ExcelCompressionUtils;
import com.xunji.standard.zip.FileRecursiveCopierUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.io.File;
import java.time.LocalDateTime;
import java.util.*;

/**
 * @Author: xuqiang_imyours
 * @Date: 2025/6/18 14:43
 * @Description:
 **/
@Slf4j
@Service
public class CaseServiceImpl extends ServiceImpl<CaseMapper, StCase> implements CaseService {
    @Resource
    CaseUploadInfoImpl caseUploadInfoImpl;
    @Resource
    CaseFileServiceImpl caseFileServiceImpl;
    @Resource
    TXjNdFlBankInformationServiceImpl ndBankAccountServiceImpl;
    @Resource
    TXjNdFlBillInformationServiceImpl ndBillingInformationServiceImpl;
    /*@Resource
    NdContactInformationServiceImpl ndContactInformationServiceImpl;*/  // 联系人注释
    @Resource
    TXjNdFlDriverInformationServiceImpl ndDriverLicenseServiceImpl;
    @Resource
    TXjNdFlCarInformationServiceImpl ndFlCarInformationServiceImpl;
    @Resource
    TXjNdFlPersonInformationServiceImpl ndPersonInformationServiceImpl;
    @Resource
    TXjNdFlHouseInformationServiceImpl tXjNdFlHouseInformationServiceImpl;
    @Resource
    TXjNdFlMessageCallServiceImpl ndSmsCallServiceImpl;
    @Resource
    TXjNdFlVoiceCallServiceImpl ndVoiceCallServiceImpl;
    @Resource
    TXjNdFlWechatInformationServiceImpl ndWechatServiceImpl;
    @Resource
    private TXjNdFlAlipayInformationServiceImpl ndAlipayServiceImpl;
    @Resource
    ExcelProcessService excelProcessService;
    @Resource
    TXjNdFlUndealServiceImpl txjNdFlUndealServiceImpl;


    @Value("${nd.service.url:}")
    private String ndUrl;
    @Value("${project_temp_path:}")
    private String projectTempPath;
    @Value("${project_temp_url:}")
    private String projectTempUrl;


    @Override
    public List<StCase> getListByUserId(String userId) {
        QueryWrapper<StCase> qw = new QueryWrapper<>();
        qw.eq("user_id", userId).orderByDesc("created_time");
        qw.eq("deleted", 0); // 只查询未删除的案件
        return this.baseMapper.selectList(qw);
    }

    @Override
    public StCase addCaseByUserId(String userId) {
        StCase stCase = new StCase();
        stCase.setId(UUIDUtil.getUUID());
        stCase.setUserId(userId);
        stCase.setName(DateUtil.getTimeStampStrWithCn());
        stCase.setCreatedTime(LocalDateTime.now());
        this.save(stCase);
        return stCase;
    }

    @Override
    public void updateCaseName(String caseId, String name) {
        UpdateWrapper<StCase> qw = new UpdateWrapper<>();
        qw.set("name", name).eq("id", caseId);
        this.update(qw);
    }

    @Override
    public void deleteCase(String caseId) {
        log.info("删除案件：" + caseId);
        this.baseMapper.deleteById(caseId);

        // todo 清理与案件相关的所有数据
        log.info("清理案件文件数据表：" + caseId);
        caseFileServiceImpl.deleteByCaseId(caseId);
        log.info("清理案件上传信息表：" + caseId);
        caseUploadInfoImpl.deleteByCaseId(caseId);

        log.info("清理案件数据分析相关表：" + caseId);
        deleteAnalysisPerson(caseId, null, null, 1);
        deleteAnalysisPerson(caseId, null, null, 2);
        deleteAnalysisPerson(caseId, null, null, 3);
        log.info("清理案件数据分析相关表完成：" + caseId);
    }

    @Override
    public void logicalDeleteCase(String caseId) {
        // 设置删除标识位为1
        StCase caseEntity = getById(caseId);
        if (caseEntity != null) {
            caseEntity.setDeleted(1);
            updateById(caseEntity);
        }
    }

    @Override
    public void restoreCase(String caseId) {
        StCase caseEntity = getById(caseId);
        if (caseEntity != null && caseEntity.getDeleted() == 1) {
            caseEntity.setDeleted(0);
            updateById(caseEntity);
        }
    }

    @Override
    public void deleteAnalysisPerson(String caseId, String xm, String sfzh, Integer type) {
        switch (type) {
            case 1:
                // 删除人员信息
                log.info("开始清理人员信息相关数据表");
                ndPersonInformationServiceImpl.deleteByCaseId(caseId, xm, sfzh);
                ndDriverLicenseServiceImpl.deleteByCaseId(caseId, xm, sfzh);
                ndFlCarInformationServiceImpl.deleteByCaseId(caseId, xm, sfzh);
                ndBankAccountServiceImpl.deleteByCaseId(caseId, xm, sfzh);
                tXjNdFlHouseInformationServiceImpl.deleteByCaseId(caseId, xm, sfzh);
                ndWechatServiceImpl.deleteByCaseId(caseId, xm, sfzh);
                ndAlipayServiceImpl.deleteByCaseId(caseId, xm, sfzh);
                log.info("清理人员信息相关数据表完成");
                break;
            case 2:
                // 删除账单
                log.info("开始清理账单相关数据表");
                ndBillingInformationServiceImpl.deleteByCaseId(caseId, xm, sfzh);
                log.info("清理账单相关数据表完成");
                break;
            case 3:
                // 删除话单
                log.info("开始清理话单相关数据表");
                ndSmsCallServiceImpl.deleteByCaseId(caseId, xm, sfzh);
                ndVoiceCallServiceImpl.deleteByCaseId(caseId, xm, sfzh);
                log.info("清理话单相关数据表完成");
                break;
            default:
                break;
        }
    }


    @Override
    public void updateByEntity(StCase stCase) {
        this.baseMapper.updateById(stCase);
    }

    @Override
    public void doParse(String caseId, Long infoId) {

        CaseUploadInfo info = caseUploadInfoImpl.getById(infoId);
        try {
            String uploadPath = info.getUploadPath(); // 上传文件路径
            // 查询是否存在文件
            List<CaseFile> files = caseFileServiceImpl.selectListByInfoIdAndCaseId(caseId, infoId);
            // 扫描是否有文件
            ArrayList<CopyFileDto> dtos = FileRecursiveCopierUtils.copyFilesRecursively(uploadPath, null, null, false);
            if (!dtos.isEmpty() && !files.isEmpty()) {
                log.info("开始调用南大解析，caseId={},infoId={}", caseId, infoId);
                // 将文件拷贝到指定目录
                String zipName = System.currentTimeMillis() + ".zip";
                String contentPath = Constant.CASE_ZIP + File.separator + caseId + File.separator + infoId + File.separator + zipName;
                String copyPath = projectTempPath + File.separator + contentPath;
                log.info("开始生成压缩文件，uploadPath: {}, copyPath: {}", uploadPath, copyPath);
                boolean res = AdvancedCompressionUtils.zip(uploadPath, copyPath);
                if (res) {
                    log.info("压缩文件成功，开始发送南大解析，caseId={},infoId={}", caseId, infoId);
                    // 生成可下载的代理文件
                    String zip_url = projectTempUrl + File.separator + contentPath;
                    HashMap<String, Object> map = new HashMap<>();
                    map.put("case_id", caseId);
                    map.put("info_id", infoId);
                    map.put("zip_url", zip_url);
                    log.info("开始发送南大解析，caseId={},infoId={},map={}", caseId, infoId, JSONObject.toJSONString(map));
                    String post = RestTemplateUtils.post(ndUrl, map, String.class);
                    log.info("南大解析结果：{}", post);
                    if (post != null) {
                        JSONObject jsonObject = JSONObject.parseObject(post);
                        int code = (int) jsonObject.get("code");
                        if (code == 0) {
                            // 记录状态
                            info.setIsSend(Constant.S_ONE); // 发送成功
                        } else {
                            // 记录状态
                            info.setIsSend(Constant.S_TWO); // 调用失败
                        }
                    } else {
                        log.error("南大解析失败，请检查南大解析服务是否正常");
                        info.setIsSend(Constant.S_TWO); // 调用失败
                    }
                }
            } else {
                info.setIsSend(Constant.S_ONE);
                info.setStatus(Constant.I_ZERO);
            }
        } catch (Exception e) {
            info.setIsSend(Constant.S_TWO);
            info.setStatus(Constant.I_ZERO);
        }
        caseUploadInfoImpl.updateById(info);
    }

    @Override
    public void doProcess(String caseId, Long infoId, String uploadFilePath, String password) {
        // 找到文件目录
        // 1. 递归解压文件

        if (password != null) {
            AdvancedCompressionUtils.recursionDecompress(uploadFilePath, password.toCharArray());
        } else {
            AdvancedCompressionUtils.recursionDecompress(uploadFilePath, null);
        }
        try {
            // 扫描文件夹，获取所有文件，不拷贝
            ArrayList<CopyFileDto> dtos = FileRecursiveCopierUtils.copyFilesRecursively(uploadFilePath, null, null, false);
            if (!dtos.isEmpty()) {
                saveCopyFile(dtos, caseId, infoId);
            }
        } catch (Exception e) {
            log.error(e.getMessage());
        }

        boolean allAnalyzed = caseFileServiceImpl.isAllAnalyzed(caseId);
        if (allAnalyzed) {
            // 文件解析完毕,更新上传号状态
            caseUploadInfoImpl.updateStatusById(infoId, Constant.I_TWO); // 文件解密完成,变更为文件解析状态

            // 触发异步请求，调用南大解析
            ExecutorUtils.execute(() -> {
                doParse(caseId, infoId); // 异步发送南大解析
            });
        }
    }

    @Override
    public List<StCase> getCaseByIds(List<String> caseIds) {
        QueryWrapper<StCase> qw = new QueryWrapper<>();
        if (caseIds != null && !caseIds.isEmpty()) {
            qw.in("id", caseIds).orderByDesc("created_time");
            return this.baseMapper.selectList(qw);
        }
        return null;
    }

    @Override
    public void saveCopyFile(ArrayList<CopyFileDto> dtos, String caseId, Long infoId) {

        ArrayList<CaseFile> caseFiles = new ArrayList<>();
        for (CopyFileDto dto : dtos) {
            CaseFile caseFile = new CaseFile();
            caseFile.setId(UUIDUtil.getUUID());
            caseFile.setInfoId(infoId);
            caseFile.setCaseId(caseId);
            caseFile.setOriginalName(dto.getOriginalName());
            caseFile.setOriginalPath(dto.getOriginalPath());
            caseFile.setCreatedTime(LocalDateTime.now());
            String extension = FilenameUtils.getExtension(new File(dto.getOriginalPath()).getAbsolutePath()).toLowerCase();
            if (Constant.ZIP_TYPE.contains(extension)) {
                caseFile.setFileType(Constant.S_TWO); // 压缩包文件读取
                caseFile.setFileStatus(Constant.S_TWO); // 压缩包读取失败
            } else if (Constant.EXCEL_TYPE.contains(extension)) {
                caseFile.setFileType(Constant.S_ONE); // excel类型
                // 判断文件是否已解密
                boolean matches = dto.getOriginalPath().matches(".*_\\[.*?\\].*");
                if (matches) {
                    caseFile.setFileStatus(Constant.S_ONE); // 无密码
                    caseFile.setFilePassword(dto.getOriginalPath().substring(dto.getOriginalPath().lastIndexOf("_[") + 2, dto.getOriginalPath().lastIndexOf("]")));
                } else {
                    // excel需判断是否加密
                    boolean res = ExcelCompressionUtils.isExcelEncrypted(dto.getOriginalPath());
                    if (res) {
                        boolean codeResult = false;
                        // 尝试密码本解密
                        List<String> codes = CodeBookCache.get(Constant.CODE_BOOK);
                        if (codes != null && !codes.isEmpty()) {
                            log.info("开始尝试密码本解密，当前excel名称：{}", dto.getOriginalPath());
                            for (String code : codes) {
                                log.info("开始尝试密码：{}", code);
                                codeResult = ExcelCompressionUtils.isExcelEncrypted(dto.getOriginalPath(), code);
                                if (codeResult) {
                                    log.info("excel密码本解压成功，当前excel名称：{}，密码{}", dto.getOriginalPath(), code);
                                    // 密码本解压成功
                                    // 变更文件名
                                    // 变更原始文件名称
                                    File file = new File(dto.getOriginalPath());
                                    String name = file.getName();
                                    String newName = name.substring(0, name.lastIndexOf(".")) + "_[" + code + "]" + name.substring(name.lastIndexOf("."));
                                    file.renameTo(new File(file.getParent() + File.separator + newName)); // 更名
                                    caseFile.setOriginalPath(file.getParent() + File.separator + newName);
                                    caseFile.setFilePassword(code);
                                    break;
                                }
                            }
                        }
                        if (codeResult) {
                            caseFile.setFileStatus(Constant.S_ONE);
                        } else {
                            caseFile.setFileStatus(Constant.S_TWO); // 读取失败，需要密码
                        }
                    } else {
                        caseFile.setFileStatus(Constant.S_ONE); // 无密码
                    }
                }
            } else {
                caseFile.setFileType(Constant.S_ONE);
                caseFile.setFileStatus(Constant.S_ONE); // 初始状态
            }
            caseFiles.add(caseFile);
        }

        caseFileServiceImpl.saveBatch(caseFiles);
        /*// 查找所有上传号
        List<CaseUploadInfo> infos = caseUploadInfoImpl.getListByCaseId(caseId);
        // 获取所有上传号id
        List<Long> infoIds = infos.stream().map(CaseUploadInfo::getId).collect(Collectors.toList());

        // 判断文件在数据库中是否已存在
        for (CaseFile caseFile : caseFiles) {
            String originalName = caseFile.getOriginalName();
            boolean exits = caseFileServiceImpl.isExits(originalName, infoIds);
            if (!exits) {
                caseFileServiceImpl.save(caseFile);
            } else {
                log.info("文件已存在，文件名称：{}，取消入库并删除源文件", originalName);
                // 清理当前文件
                File file1 = new File(caseFile.getOriginalPath());
                log.info("删除源文件：{}", caseFile.getOriginalPath());
                file1.delete();
            }
        }*/
    }

    @Override
    public List<CaseAnalysisListResponse2> doPageInformation2(List<TXjNdFlPersonInformation> persons, String caseId) {
        ArrayList<CaseAnalysisListResponse2> list = new ArrayList<>();
        for (TXjNdFlPersonInformation person : persons) {
            CaseAnalysisListResponse2 response = new CaseAnalysisListResponse2();
            // 1. 添加用户信息
            PersonInformationResponse informationResponse = new PersonInformationResponse();
            informationResponse.setId(person.getId());
            informationResponse.setXm(person.getXm());
            informationResponse.setSfzh(person.getSfzh());
            informationResponse.setXb(person.getXb());
            LocalDateTime csrq = person.getCsrq();
            if (csrq != null) {
                informationResponse.setCsrq(csrq);
                informationResponse.setAge(LocalDateTime.now().getYear() - csrq.getYear());
            }else{
                //根据person.getSfzh()身份证号获取出生日期
                // 从身份证号中提取出生日期
                String birthDateStr = person.getSfzh().substring(6, 14);
                csrq = LocalDateTime.of(Integer.parseInt(birthDateStr.substring(0, 4)),
                        Integer.parseInt(birthDateStr.substring(4, 6)),
                        Integer.parseInt(birthDateStr.substring(6, 8)), 0, 0);
                informationResponse.setCsrq(csrq);
                informationResponse.setAge(LocalDateTime.now().getYear() - csrq.getYear());
            }
            response.setPersonInformation(informationResponse);
            // 2. 添加联系方式
            String lxfs = person.getLxfs();
            List<String> phones = null;
            if (StringUtils.isNoneEmpty(lxfs)) {
                phones = new ArrayList<>(Arrays.asList(lxfs.split(",")));
                response.setPhones(phones);
            }
            // 3. 添加车辆信息
            List<TXjNdFlCarInformation> ndFlCarInformationList = ndFlCarInformationServiceImpl.selectListByCaseIdAndInfoId(caseId, null, person.getXm(), person.getSfzh());
            ArrayList<CarInformationResponse> carInformationResponses = new ArrayList<>();
            Set<String> existingStrings = new HashSet<>();
            if (!ndFlCarInformationList.isEmpty()) {
                for (TXjNdFlCarInformation ndFlCarInformation : ndFlCarInformationList) {
                    CarInformationResponse carInformationResponse = new CarInformationResponse();
                    carInformationResponse.setId(ndFlCarInformation.getId());
                    carInformationResponse.setHphm(ndFlCarInformation.getHphm());
                    carInformationResponse.setZwpp(ndFlCarInformation.getZwpp());
                    // 只有当车牌号不存在时才添加
                    if (!existingStrings.contains(carInformationResponse.getHphm())) {
                        carInformationResponses.add(carInformationResponse);
                        existingStrings.add(carInformationResponse.getHphm());
                    }
                }
                response.setCarInformation(carInformationResponses);
            }
            // 4. 添加账户信息
            // 银行卡
            List<TXjNdFlBankInformation> ndFlBankInformationList = ndBankAccountServiceImpl.selectListByCaseIdAndInfoId(caseId, null, person.getXm(), person.getSfzh());
            ArrayList<AccountInformationResponse> accountInformationResponses = new ArrayList<>();
            // 使用Set存储已存在的Account，提高查找效率
            existingStrings.clear();
            if (!ndFlBankInformationList.isEmpty()) {
                for (TXjNdFlBankInformation ndFlBankInformation : ndFlBankInformationList) {
                    AccountInformationResponse accountInformationResponse = new AccountInformationResponse();
                    accountInformationResponse.setId(ndFlBankInformation.getId());
                    accountInformationResponse.setAccount(ndFlBankInformation.getKhwd() + " " + ndFlBankInformation.getKh());
                    accountInformationResponse.setAccountType(1);

                    // 只有当Account不存在时才添加
                    if (!existingStrings.contains(accountInformationResponse.getAccount())) {
                        accountInformationResponses.add(accountInformationResponse);
                        existingStrings.add(accountInformationResponse.getAccount());
                    }
                }

            }
            // 微信
            List<TXjNdFlWechatInformation> ndFlWechatInformationList = ndWechatServiceImpl.selectListByCaseIdAndInfoId(caseId, null, person.getXm(), person.getSfzh());
            if (!ndFlWechatInformationList.isEmpty()) {
                for (TXjNdFlWechatInformation ndFlWechatInformation : ndFlWechatInformationList) {
                    AccountInformationResponse accountInformationResponse = new AccountInformationResponse();
                    accountInformationResponse.setId(ndFlWechatInformation.getId());
                    accountInformationResponse.setAccount(ndFlWechatInformation.getWxid());
                    accountInformationResponse.setAccountType(2);
                    if (!existingStrings.contains(accountInformationResponse.getAccount())) {
                        accountInformationResponses.add(accountInformationResponse);
                        existingStrings.add(accountInformationResponse.getAccount());
                    }
                }
            }
            // 支付宝
            if (phones != null && !phones.isEmpty()) {
                List<TXjNdFlAlipayInformation> ndFlAlipayInformationList = ndAlipayServiceImpl.selectListByCaseIdAndInfoId(caseId, null, person.getXm(), person.getSfzh(), phones);
                if (!ndFlAlipayInformationList.isEmpty()) {
                    for (TXjNdFlAlipayInformation ndFlAlipayInformation : ndFlAlipayInformationList) {
                        AccountInformationResponse accountInformationResponse = new AccountInformationResponse();
                        accountInformationResponse.setId(ndFlAlipayInformation.getId());
                        accountInformationResponse.setAccount(ndFlAlipayInformation.getZfbid());
                        accountInformationResponse.setAccountType(3);
                        if (!existingStrings.contains(accountInformationResponse.getAccount())) {
                            accountInformationResponses.add(accountInformationResponse);
                            existingStrings.add(accountInformationResponse.getAccount());
                        }
                    }
                }
            }
            response.setAccountInformation(accountInformationResponses);
            // 5. 添加房产信息
            List<TXjNdFlHouseInformation> ndFlHouseInformationList = tXjNdFlHouseInformationServiceImpl.selectListByCaseIdAndInfoId(caseId, null, person.getXm(), person.getSfzh());

            ArrayList<HouseInformationResponse> houseInformationResponses = new ArrayList<>();
            if (!ndFlHouseInformationList.isEmpty()) {
                for (TXjNdFlHouseInformation ndFlHouseInformation : ndFlHouseInformationList) {
                    HouseInformationResponse houseInformationResponse = new HouseInformationResponse();
                    houseInformationResponse.setId(ndFlHouseInformation.getId());
                    houseInformationResponse.setAddress(ndFlHouseInformation.getFwzl());
                    houseInformationResponses.add(houseInformationResponse);
                }
                response.setHouseInformation(houseInformationResponses);
            }
            list.add(response);
        }
        return list;
    }


    @Override
    public List<CaseAnalysisListResponse> doPageInformation(List<TXjNdFlPersonInformation> persons, Integer type) {
        ArrayList<CaseAnalysisListResponse> responses = new ArrayList<>();
        for (TXjNdFlPersonInformation person : persons) {
            switch (type) {
                case 0:
                    // 查询所有信息
                    ArrayList<CaseAnalysisListResponse> responses01 = doGetFileResponse(person, 1);
                    if (!responses01.isEmpty()) {
                        responses.addAll(responses01);
                    }
                    ArrayList<CaseAnalysisListResponse> responses02 = doGetFileResponse(person, 2);
                    if (!responses02.isEmpty()) {
                        responses.addAll(responses02);
                    }
                    ArrayList<CaseAnalysisListResponse> responses03 = doGetFileResponse(person, 3);
                    if (!responses03.isEmpty()) {
                        responses.addAll(responses03);
                    }
                    break;
                case 1:
                    // 查询人员信息
                    ArrayList<CaseAnalysisListResponse> responses1 = doGetFileResponse(person, 1);
                    if (!responses1.isEmpty()) {
                        responses.addAll(responses1);
                    }
                    break;
                case 2:
                    // 查询账单信息
                    ArrayList<CaseAnalysisListResponse> responses2 = doGetFileResponse(person, 2);
                    if (!responses2.isEmpty()) {
                        responses.addAll(responses2);
                    }
                    break;
                case 3:
                    // 查询话单信息
                    ArrayList<CaseAnalysisListResponse> responses3 = doGetFileResponse(person, 3);
                    if (!responses3.isEmpty()) {
                        responses.addAll(responses3);
                    }
                    break;
                default:
                    break;
            }
        }
        return responses;
    }

    @Override
    public String doExport(CaseExportRequest request) {
        String caseId = request.getCaseId();
        List<ExportData> exportData = request.getExportData();
        ArrayList<String> fileNameList = new ArrayList<>(); // 文件名称列表
        String contentPath = Constant.CASE_EXCEL + File.separator + caseId + File.separator + System.currentTimeMillis() + File.separator;
        String folderPath = projectTempPath + File.separator + contentPath;
        FileUtil.createDir(folderPath);
        for (ExportData data : exportData) {
            String xm = data.getXm();
            String sfzh = data.getSfzh();
            Integer type = data.getType(); // 数据类别  1 人员信息 2 账单 3 话单
            switch (type) {
                case 1:
                    doPersonExcelExport(fileNameList, caseId, xm, sfzh, folderPath);
                    break;
                case 2:
                    doBillingExcelExport(fileNameList, caseId, xm, sfzh, folderPath);
                    break;
                case 3:
                    doCallExcelExport(fileNameList, caseId, xm, sfzh, folderPath);
                    break;
                default:
                    log.info("数据类别错误，type:{}", type);
                    break;
            }
        }
        return getDownloadFileUrl(fileNameList, caseId, contentPath, folderPath);
    }

    @Override
    public CasePersonInformationResponse doInformationInfo(String caseId, Long personId) {
        CasePersonInformationResponse response = new CasePersonInformationResponse();
        TXjNdFlPersonInformation personInformation = ndPersonInformationServiceImpl.getById(personId);
        if (personInformation != null) {
            String xm = personInformation.getXm(); //  姓名
            String sfzh = personInformation.getSfzh(); // 身份证号
            // 人员信息表
            response.setPersonInformation(personInformation);
            // 机动车信息表
            List<TXjNdFlCarInformation> carInformation = ndFlCarInformationServiceImpl.selectListByCaseIdAndInfoId(caseId, null, xm, sfzh);
            response.setCarInformation(carInformation);
            // 房产信息表
            List<TXjNdFlHouseInformation> houseInformation = tXjNdFlHouseInformationServiceImpl.selectListByCaseIdAndInfoId(caseId, null, xm, sfzh);
            response.setHouseInformation(houseInformation);
            // 银行账户信息表
            List<TXjNdFlBankInformation> bankInformation = ndBankAccountServiceImpl.selectListByCaseIdAndInfoId(caseId, null, xm, sfzh);
            response.setBankInformation(bankInformation);
            // 支付宝信息表
            List<TXjNdFlAlipayInformation> alipayInformation = ndAlipayServiceImpl.selectListByCaseIdAndInfoId(caseId, null, xm, sfzh, null);
            response.setAlipayInformation(alipayInformation);
            // 微信信息表
            List<TXjNdFlWechatInformation> wechatInformation = ndWechatServiceImpl.selectListByCaseIdAndInfoId(caseId, null, xm, sfzh);
            response.setWechatInformation(wechatInformation);
        }
        return response;
    }

    @Override
    public DataStatisticsResponse dataStatistics(String caseId) {
        DataStatisticsResponse response = new DataStatisticsResponse();
        // 总人数
        List<TXjNdFlPersonInformation> persons = ndPersonInformationServiceImpl.selectListByCaseId(caseId, null);
        // 数据去重，去除persons中相同的数据
        HashMap<String, TXjNdFlPersonInformation> map = new HashMap<>();
        for (TXjNdFlPersonInformation person : persons) {
            String key = person.getXm() + person.getSfzh();
            if (!map.containsKey(key)) {
                map.put(key, person);
            }
        }
        persons = new ArrayList<>(map.values());
        response.setTotalCount(persons.size());

        // 上传文件数
        List<CaseFile> files = caseFileServiceImpl.selectListByCaseId(caseId);
        response.setUploadFileCount(files.size());
        // 已解析文件数
        List<TXjNdFlUndeal> undeals = txjNdFlUndealServiceImpl.selectListByCaseId(caseId);
        response.setAnalysisFileCount(files.size() - undeals.size());
        // 未处理
        response.setUnprocessedCount(undeals.size());

        // 账单总数
        List<TXjNdFlBillInformation> billings = ndBillingInformationServiceImpl.selectListByCaseId(caseId);
        response.setBillCount(billings.size());
        // 话单总数
        List<TXjNdFlVoiceCall> voiceCalls = ndVoiceCallServiceImpl.selectListByCaseId(caseId);
        response.setVoiceCount(voiceCalls.size());
        return response;
    }

    @Override
    public void updateOwnerInfo(CaseOwnerUpdateRequest request) {
        String caseId = request.getCaseId(); // 案件id
        Long personId = request.getPersonId(); // 人员id
        TXjNdFlPersonInformation personInformation = ndPersonInformationServiceImpl.getById(personId);
        Long ownerId = request.getOwnerId(); // 新归属人id
        TXjNdFlPersonInformation ownerInformation = ndPersonInformationServiceImpl.getById(ownerId);
        Integer type = request.getType(); // 修改类型  1 联系方式 2 车辆信息 3 账户信息 4 不动产信息
        switch (type) {
            case 1: // 联系方式
                log.info("开始修改联系方式，将原归属人：{}替换为新归属人：{}，修改内容为手机号：{}", personId, ownerId, request.getCommonModifyContent());
                ndPersonInformationServiceImpl.updateOwnerInfo(caseId, personInformation, ownerInformation, request.getCommonModifyContent());
                break;
            case 2: // 车辆信息
                log.info("开始修改车辆信息，将原归属人：{}替换为新归属人：{}，修改内容为车辆id：{}", personId, ownerId, request.getCommonModifyId());
                ndFlCarInformationServiceImpl.updateOwnerInfo(caseId, personInformation, ownerInformation, request.getCommonModifyId());
                break;
            case 3: // 账户信息
                log.info("开始修改账户信息，将原归属人：{}替换为新归属人：{}，修改内容为账户id：{}", personId, ownerId, request.getCommonModifyId());
                // 检测修改的是那种账户 commonModifyId
                if (request.getCommonModifyId() != null) {
                    // 银行账户
                    TXjNdFlBankInformation ndFlBankInformation = ndBankAccountServiceImpl.getById(request.getCommonModifyId());
                    if (ndFlBankInformation != null) {
                        ndBankAccountServiceImpl.updateOwnerInfo(caseId, personInformation, ownerInformation, request.getCommonModifyId());
                    }
                    // 微信
                    TXjNdFlWechatInformation ndFlWechatInformation = ndWechatServiceImpl.getById(request.getCommonModifyId());
                    if (ndFlWechatInformation != null) {
                        ndWechatServiceImpl.updateOwnerInfo(caseId, personInformation, ownerInformation, request.getCommonModifyId());
                    }
                    // 支付宝
                    TXjNdFlAlipayInformation ndFlAlipayInformation = ndAlipayServiceImpl.getById(request.getCommonModifyId());
                    if (ndFlAlipayInformation != null) {
                        ndAlipayServiceImpl.updateOwnerInfo(caseId, personInformation, ownerInformation, request.getCommonModifyId());
                    }
                }
                break;
            case 4: // 不动产信息
                log.info("开始修改不动产信息，将原归属人：{}替换为新归属人：{}，修改内容为不动产id：{}", personId, ownerId, request.getCommonModifyId());
                tXjNdFlHouseInformationServiceImpl.updateOwnerInfo(caseId, personInformation, ownerInformation, request.getCommonModifyId());
                break;
            default:
                log.info("未匹配到正确的修改类型，type:{}", type);
                break;
        }


    }

    private ArrayList<CaseAnalysisListResponse> doGetFileResponse(TXjNdFlPersonInformation person, Integer type) {
        ArrayList<CaseAnalysisListResponse> responses = new ArrayList<>();
        CaseAnalysisListResponse response = new CaseAnalysisListResponse();
        String xm = person.getXm();
        String sfzh = person.getSfzh();
        String lxfs = person.getLxfs(); // 联系方式查找
        ArrayList<String> lxfsList = new ArrayList<>();
        if (!StringUtils.isEmpty(lxfs)) {
            String[] split = lxfs.split(",");
            for (String s : split) {  // 去除空数据
                if (!StringUtils.isEmpty(s)) {
                    lxfsList.add(s);
                }
            }
        }
        response.setXm(xm);
        response.setSfzh(sfzh);
        response.setType(type);
        switch (type) {
            case 1:
                // 人员信息
                List<CaseFileResponse> caseFiles1 = getPeopleInfo(person.getCaseId(), person.getInfoId(), xm, sfzh, lxfsList);
                response.setNumber(caseFiles1.size());
                if (!caseFiles1.isEmpty()) {
                    response.setCaseFiles(caseFiles1);
                    responses.add(response);
                }
                break;
            case 2:
                // 账单信息
                List<CaseFileResponse> caseFiles2 = getBillingInfo(person.getCaseId(), person.getInfoId(), xm, sfzh, lxfsList);
                response.setNumber(caseFiles2.size());
                if (!caseFiles2.isEmpty()) {
                    response.setCaseFiles(caseFiles2);
                    responses.add(response);
                }
                break;
            case 3:
                // 话单信息
                List<CaseFileResponse> caseFiles3 = getCallInfo(person.getCaseId(), person.getInfoId(), xm, sfzh, lxfsList);
                response.setNumber(caseFiles3.size());
                if (!caseFiles3.isEmpty()) {
                    response.setCaseFiles(caseFiles3);
                    responses.add(response);
                }
                break;
            default:
                break;
        }
        return responses;
    }

    @Override
    public String doExportAll(String caseId) {
        log.info("开始导出所有信息,当前案件caseId:{}", caseId);
        // 查询人员信息表
        log.info("开始查询人员信息表");
        List<TXjNdFlPersonInformation> persons = ndPersonInformationServiceImpl.selectListByCaseId(caseId, null);
        log.debug("查询到人员信息表：{}", persons);
        if (persons == null) return null;

        // 数据去重，去除persons中相同的数据
        HashMap<String, TXjNdFlPersonInformation> map = new HashMap<>();
        for (TXjNdFlPersonInformation person : persons) {
            String key = person.getXm() + person.getSfzh();
            if (!map.containsKey(key)) {
                map.put(key, person);
            }
        }
        persons = new ArrayList<>(map.values());

        ArrayList<String> fileNameList = new ArrayList<>(); // 文件名称列表
        String contentPath = Constant.CASE_EXCEL + File.separator + caseId + File.separator + System.currentTimeMillis() + File.separator;
        String folderPath = projectTempPath + File.separator + contentPath;
        FileUtil.createDir(folderPath);
        for (TXjNdFlPersonInformation person : persons) {
            String xm = person.getXm();
            String sfzh = person.getSfzh();
            doPersonExcelExport(fileNameList, caseId, xm, sfzh, folderPath);
            doBillingExcelExport(fileNameList, caseId, xm, sfzh, folderPath);
            doCallExcelExport(fileNameList, caseId, xm, sfzh, folderPath);
        }
        return getDownloadFileUrl(fileNameList, caseId, contentPath, folderPath);
    }


    private String getDownloadFileUrl(ArrayList<String> fileNameList, String caseId, String contentPath, String folderPath) {
        // 生成下载链接
        if (fileNameList.isEmpty()) {
            return null;
        }
        if (fileNameList.size() == 1) {
            // 单个文件直接导出
            return projectTempUrl + File.separator + contentPath + fileNameList.get(0);
        }
        // 生成压缩包
        String zipName = System.currentTimeMillis() + ".zip";
        String contextPath = Constant.CASE_EXCEL + File.separator + caseId + File.separator + zipName;
        boolean res = AdvancedCompressionUtils.zip(folderPath, projectTempPath + File.separator + contextPath);
        if (res) {
            return projectTempUrl + File.separator + contextPath;
        }
        return null;
    }

    private void doCallExcelExport(ArrayList<String> fileNameList, String caseId, String xm, String sfzh, String folderPath) {
        log.info("开始查询话单信息");
        List<String> lxhmList = ndPersonInformationServiceImpl.getlxfsList(caseId, null, xm, sfzh);
        /*// 查询人员信息，根据人员信息查找联系方式
        List<TXjNdFlPersonInformation> persons1 = ndPersonInformationServiceImpl.selectListByCaseIdAndXmAndSfzh(caseId, xm, sfzh);
        if (persons1 != null) {
            log.info("未查询到人员信息，跳过话单导出！！");
            return;
        }
        ArrayList<String> lxfslist = new ArrayList<>();
        for (TXjNdFlPersonInformation person : persons1) {
            String lxfs = person.getLxfs();
            if (!StringUtils.isEmpty(lxfs)) {
                String[] split = lxfs.split(",");
                lxfslist.addAll(Arrays.asList(split));
            }
        }

        // 去重lxhm
        Set<String> lxhmSet = new HashSet<>();
        for (String lxhm : lxfslist) {
            if (StringUtils.isEmpty(lxhm)) continue;
            lxhmSet.add(lxhm);
        }
        // hashset转list
        List<String> lxhmList = new ArrayList<>(lxhmSet);*/
        List<TXjNdFlVoiceCall> voiceCalls = ndVoiceCallServiceImpl.selectListByCaseIdAndXmAndSfzh(caseId, lxhmList);
        if (voiceCalls != null && !voiceCalls.isEmpty()) {
            String sheetName = "语音通话信息表";
            String fileName = xm + "-" + sfzh + "-" + "语音通话信息表" + ".xlsx";
            fileNameList.add(fileName);
            String path = folderPath + fileName;
            log.info("开始生成语音通话信息表的Excel文件：{}", path);
            excelProcessService.processVoiceCallExcel(path, sheetName, voiceCalls);
        }

        List<TXjNdFlMessageCall> smsCalls = ndSmsCallServiceImpl.selectListByCaseIdAndXmAndSfzh(caseId, lxhmList);
        if (smsCalls != null && !smsCalls.isEmpty()) {
            String sheetName = "短信通话信息表";
            String fileName = xm + "-" + sfzh + "-" + "短信通话信息表" + ".xlsx";
            fileNameList.add(fileName);
            String path = folderPath + fileName;
            log.info("开始生成短信通话信息表的Excel文件：{}", path);
            excelProcessService.processSmsCallExcel(path, sheetName, smsCalls);
        }
    }

    private void doBillingExcelExport(ArrayList<String> fileNameList, String caseId, String xm, String sfzh, String folderPath) {
        log.info("开始查询账单信息");
        List<TXjNdFlBillInformation> billings = ndBillingInformationServiceImpl.selectListByCaseIdAndXmAndSfzh(caseId, xm, sfzh);
        if (billings != null && !billings.isEmpty()) {
            String sheetName = "账单信息表";
            String fileName = xm + "-" + sfzh + "-" + "账单信息表" + ".xlsx";
            fileNameList.add(fileName);
            String path = folderPath + fileName;
            excelProcessService.processBillingInformationExcel(path, sheetName, billings);
        }
    }

    private void doPersonExcelExport(ArrayList<String> fileNameList, String caseId, String xm, String sfzh, String folderPath) {
        log.info("开始查询人员信息");
        List<TXjNdFlPersonInformation> persons = ndPersonInformationServiceImpl.selectListByCaseIdAndXmAndSfzh(caseId, xm, sfzh);
        if (persons != null) { // 人员不为空为基础进行数据填充
            // 人员信息表
            TXjNdFlPersonInformation information = persons.get(0);
            // 机动车信息表
            List<TXjNdFlCarInformation> vehicles = ndFlCarInformationServiceImpl.selectListByCaseIdAndXmAndSfzh(caseId, xm, sfzh);
            // 房产信息表
            List<TXjNdFlHouseInformation> realEstates = tXjNdFlHouseInformationServiceImpl.selectListByCaseIdAndXmAndSfzh(caseId, xm, sfzh);
            // 银行账户信息表
            List<TXjNdFlBankInformation> bankAccounts = ndBankAccountServiceImpl.selectListByCaseIdAndXmAndSfzh(caseId, xm, sfzh);
            // 支付宝信息表
            List<TXjNdFlAlipayInformation> alipays = ndAlipayServiceImpl.selectListByCaseIdAndXmAndSfzh(caseId, xm, sfzh);
            // 微信信息表
            List<TXjNdFlWechatInformation> wechats = ndWechatServiceImpl.selectListByCaseIdAndXmAndSfzh(caseId, xm, sfzh);
            String sheetName = "人员档案表";
            String fileName = xm + "-" + sfzh + "-" + "人员档案表" + ".xlsx";
            fileNameList.add(fileName);
            String path = folderPath + fileName;
            log.info("开始生成人员信息表的Excel文件：{}", path);
            excelProcessService.processPersonInformationExcel(path, sheetName, information, vehicles, realEstates, bankAccounts, alipays, wechats);
        }
    }

    // 查询话单信息
    private List<CaseFileResponse> getCallInfo(String caseId, Long infoId, String xm, String sfzh, ArrayList<String> lxfsList) {
        ArrayList<CaseFileResponse> responses = new ArrayList<>();
        ArrayList<String> sjlyList = new ArrayList<>(); // 去重数据来源
        // 根据话单表查询数据条数，取出数据来源
        // 1. 语音通话信息表
        log.info("开始查询语音通话信息表");
        List<TXjNdFlVoiceCall> list1 = ndVoiceCallServiceImpl.selectListByCaseIdAndInfoId(caseId, infoId, xm, sfzh);
        log.debug("查询到语音通话信息表：{}", list1);
        if (list1 != null && !list1.isEmpty()) {
            for (TXjNdFlVoiceCall call : list1) {
                String ywj = call.getYwj(); // 数据来源
                if (!sjlyList.contains(ywj)) {
                    sjlyList.add(ywj);
                }
            }
        }
        // 2. 短信通话信息表
        log.info("开始查询短信通话信息表");
        List<TXjNdFlMessageCall> list2 = ndSmsCallServiceImpl.selectListByCaseIdAndInfoId(caseId, infoId, xm, sfzh);
        log.debug("查询到短信通话信息表：{}", list2);
        if (list2 != null && !list2.isEmpty()) {
            for (TXjNdFlMessageCall call : list2) {
                String ywj = call.getYwj(); // 数据来源
                if (!sjlyList.contains(ywj)) {
                    sjlyList.add(ywj);
                }
            }
        }
        for (String sjly : sjlyList) {
            log.info("话单信息数据来源：{}", sjly);
            responses.addAll(findFileNameMsg(sjly, caseId, infoId));
        }
        return responses;
    }

    // 查询账单信息
    private List<CaseFileResponse> getBillingInfo(String caseId, Long infoId, String xm, String sfzh, ArrayList<String> lxfsList) {
        ArrayList<CaseFileResponse> responses = new ArrayList<>();
        // 根据账单表查询数据条数，取出数据来源
        log.info("开始查询账单信息表");
        List<TXjNdFlBillInformation> list = ndBillingInformationServiceImpl.selectListByCaseIdAndInfoId(caseId, infoId, xm, sfzh);
        log.debug("查询到账单信息表：{}", list);
        if (list != null && !list.isEmpty()) {
            ArrayList<String> sjlyList = new ArrayList<>();
            for (TXjNdFlBillInformation bi : list) {
                String ywj = bi.getYwj(); // 数据来源
                if (!sjlyList.contains(ywj)) {
                    sjlyList.add(ywj);
                }
            }
            for (String sjly : sjlyList) {
                log.info("账单信息表数据来源：{}", sjly);
                responses.addAll(findFileNameMsg(sjly, caseId, infoId));
            }
        }
        return responses;
    }


    // 查询人员信息
    private List<CaseFileResponse> getPeopleInfo(String caseId, Long infoId, String xm, String sfzh, ArrayList<String> lxfsList) {
        ArrayList<CaseFileResponse> responses = new ArrayList<>();
        ArrayList<String> twjList = new ArrayList<>(); // 去重数据来源
        // 支付宝账户信息
        log.info("开始查询支付宝账户信息");
        List<TXjNdFlAlipayInformation> list = ndAlipayServiceImpl.selectListByCaseIdAndInfoId(caseId, infoId, xm, sfzh, lxfsList);
        if (list != null && !list.isEmpty()) {
            for (TXjNdFlAlipayInformation alipay : list) {
                String ywj = alipay.getYwj(); // 数据来源
                if (!twjList.contains(ywj)) {
                    twjList.add(ywj);
                }
            }
        }
        // 银行账户信息
        log.info("开始查询银行账户信息");
        List<TXjNdFlBankInformation> list1 = ndBankAccountServiceImpl.selectListByCaseIdAndInfoId(caseId, infoId, xm, sfzh);
        if (list1 != null && !list1.isEmpty()) {
            for (TXjNdFlBankInformation bi : list1) {
                String ywj = bi.getYwj(); // 数据来源
                if (!twjList.contains(ywj)) {
                    twjList.add(ywj);
                }
            }
        }

        // 驾驶人信息表
        log.info("开始查询驾驶人信息表");
        List<TXjNdFlDriverInformation> list3 = ndDriverLicenseServiceImpl.selectListByCaseIdAndInfoId(caseId, infoId, xm, sfzh);
        if (list3 != null && !list3.isEmpty()) {
            for (TXjNdFlDriverInformation dl : list3) {
                String ywj = dl.getYwj(); // 数据来源
                if (!twjList.contains(ywj)) {
                    twjList.add(ywj);
                }
            }
        }
        // 机动车信息表
        log.info("开始查询机动车信息表");
        List<TXjNdFlCarInformation> list4 = ndFlCarInformationServiceImpl.selectListByCaseIdAndInfoId(caseId, infoId, xm, sfzh);
        if (list4 != null && !list4.isEmpty()) {
            for (TXjNdFlCarInformation mv : list4) {
                String ywj = mv.getYwj(); // 数据来源
                if (!twjList.contains(ywj)) {
                    twjList.add(ywj);
                }
            }
        }
        // 人员基本信息表
        log.info("开始查询人员基本信息表");
        List<TXjNdFlPersonInformation> list5 = ndPersonInformationServiceImpl.selectListByCaseIdAndInfoId(caseId, infoId, xm, sfzh);
        if (list5 != null && !list5.isEmpty()) {
            for (TXjNdFlPersonInformation pi : list5) {
                String ywj = pi.getYwj(); // 数据来源
                if (!twjList.contains(ywj)) {
                    twjList.add(ywj);
                }
            }
        }
        // 不动产信息表
        log.info("开始查询不动产信息表");
        List<TXjNdFlHouseInformation> list6 = tXjNdFlHouseInformationServiceImpl.selectListByCaseIdAndInfoId(caseId, infoId, xm, sfzh);
        if (list6 != null && !list6.isEmpty()) {
            for (TXjNdFlHouseInformation re : list6) {
                String ywj = re.getYwj(); // 数据来源
                if (!twjList.contains(ywj)) {
                    twjList.add(ywj);
                }
            }
        }
        // 微信开户信息表
        log.info("开始查询微信开户信息表");
        List<TXjNdFlWechatInformation> list7 = ndWechatServiceImpl.selectListByCaseIdAndInfoId(caseId, infoId, xm, sfzh);
        if (list7 != null && !list7.isEmpty()) {
            for (TXjNdFlWechatInformation wechat : list7) {
                String ywj = wechat.getYwj(); // 数据来源
                if (!twjList.contains(ywj)) {
                    twjList.add(ywj);
                }
            }
        }

        for (String ywj : twjList) {
            log.info("人员信息表数据来源：{}", ywj);
            responses.addAll(findFileNameMsg(ywj, caseId, infoId));
        }
        return responses;
    }


    @Override
    public StCase getCaseById(String caseId) {
        LambdaQueryWrapper<StCase> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(StCase::getId, caseId);
        queryWrapper.eq(StCase::getDeleted, 0); // 只查询未删除的案件
        return getOne(queryWrapper);
    }

    private ArrayList<CaseFileResponse> findFileNameMsg(String sjly, String caseId, Long infoId) {
        ArrayList<CaseFileResponse> responses = new ArrayList<>();
        String fileName = extractFileNameWithExtension(sjly);
        log.info("取出完整名称，文件名：{}", fileName);
        if (fileName != null) {
            // 根据文件名查找
            List<CaseFile> files = caseFileServiceImpl.selectListByInfoIdAndFileName(caseId, infoId, fileName);
            log.info("根据文件名查找，结果：{}", files);
            if (files != null && !files.isEmpty()) {
                for (CaseFile file : files) {
                    CaseFileResponse cs = CaseFileResponse.getCaseFileResponse(file);
                    responses.add(cs);
                }
            }
        }
        return responses;
    }


    /**
     * 提取相对路径中的文件名称（仅当文件名包含后缀名时返回）
     *
     * @param relativePath 相对路径（如 "src/main/java/Example.java" 或 "docs\\images\\logo.png"）
     * @return 文件名称（如 "Example.java"），若路径无效或文件名无后缀则返回 null
     */
    public static String extractFileNameWithExtension(String relativePath) {
        if (relativePath == null || relativePath.trim().isEmpty()) {
            return null;
        }

        // 统一替换为当前系统的文件分隔符
        String normalizedPath = relativePath.replace('/', File.separatorChar).replace('\\', File.separatorChar);

        // 移除末尾的分隔符（如果存在）
        if (normalizedPath.endsWith(File.separator)) {
            normalizedPath = normalizedPath.substring(0, normalizedPath.length() - 1);
        }

        // 提取最后一个分隔符后的内容
        int lastSeparatorIndex = normalizedPath.lastIndexOf(File.separatorChar);
        String fileName = (lastSeparatorIndex >= 0) ? normalizedPath.substring(lastSeparatorIndex + 1) : normalizedPath;

        // 检查文件名是否包含后缀名（要求：至少有一个点，且点不在开头/结尾位置）
        int dotIndex = fileName.lastIndexOf('.');
        if (dotIndex <= 0 || dotIndex == fileName.length() - 1) {
            return null; // 无有效后缀名
        }

        return fileName;
    }
}
